<?php

/**
 * This file is part of the Framework03 PHP framework.
 * @author Walter Tamboer
 * @package Framework03
 */

/**
 * This class is able to render html pages and is able to parse php variables in it.
 */
class FW_View_Html extends FW_View_Abstract
{
    /** @const The XHTML 1.0 Strict doctype. */
    const DOCTYPE_XHTML1_STRICT = 0x1;

    /** @const The XHTML 1.0 Transitional doctype. */
    const DOCTYPE_XHTML1_TRANSITIONAL = 0x2;

    /** @const The XHTML 1.0 Frameset doctype. */
    const DOCTYPE_XHTML1_FRAMESET = 0x4;

    /** @const The HTML 4.0 Strict doctype. */
    const DOCTYPE_HTML4_STRICT = 0x8;

    /** @const The HTML 4.0 Loose doctype. */
    const DOCTYPE_HTML4_LOOSE = 0x16;

    /** @const The HTML 4.0 Frameset doctype. */
    const DOCTYPE_HTML4_FRAMESET = 0x32;

    /**
     * @var int The default doc type used for HTML pages.
     */
    private static $defaultDocType = self::DOCTYPE_XHTML1_STRICT;

    /**
     * @var string The extensions of the file to render.
     */
    private $extension = '.phtml';
    
    /**
     * @var FW_Layout_Abstract The layout helper to use.
     */
    private $layout = null;
	
	/**
	 * @var bool Whether or not to use the layout.
	 */
	private $layoutEnabled = true;
    
    /**
     * @var FW_Layout_Abstract The default layout helper to use.
     */
    private static $defaultLayout = null;

    /**
     * Initializes a new instance of this class.
     */
    public function __construct()
    {
        $this->layout = self::$defaultLayout;
    }

    /**
     * Sets the default layout to use.
     * @param $layout The default layout to set.
     */
    public static function setDefaultLayout(FW_Layout_Abstract $layout)
    {
        self::$defaultLayout = $layout;
    }
    
	/**
	 * Gets the layout which is used.
	 * @return FW_Layout_Abstract
	 */
    public function getLayout()
    {
        return $this->layout;
    }
	
	/**
	 * @brief Enables the usage of the layout.
	 * @return FW_View_Html
	 */
	public function enableLayout()
	{
		$this->layoutEnabled = true;
	}
	
	/**
	 * @brief Disables the usage of the layout.
	 * @return FW_View_Html
	 */
	public function disableLayout()
	{
		$this->layoutEnabled = false;
	}

    /**
     * Sets the default doctype used for HTML pages.
     * @param int $DocType The doctype that should be set.
     */
    public static function setDefaultDocType($DocType)
    {
        self::$defaultDocType = $DocType;
    }

    /**
     * Gets the doctype decleration.
     * @return string
     */
    public function getDocTypeDecleration()
    {
        switch (self::$defaultDocType)
        {
        case self::DOCTYPE_XHTML1_STRICT:
            return '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';

        case self::DOCTYPE_XHTML1_TRANSITIONAL:
            return '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';

        case self::DOCTYPE_XHTML1_FRAMESET:
            return '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">';
            
        case self::DOCTYPE_HTML4_STRICT:
            return '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">';

        case self::DOCTYPE_HTML4_LOOSE:
            return '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">';

        case self::DOCTYPE_HTML4_FRAMESET:
            return '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">';
        }
        
        return '';
    }

    /**
     * Gets the path of where controllers can be found.
     * @param FW_Controller_Action $controller The controller that wants the rendering to be done.
     * @param string $actionName The name of the action that wants the rendering to be done.
     * @return string Returns the path to the template file.
     */
    public function getPath(FW_Controller_Action $controller, $actionName)
    {
        $dispatcher = $controller->getDispatcher();

        $directory = $dispatcher->getControllerDirectory();

        $path = dirname($directory)
            . DIRECTORY_SEPARATOR
            . 'views'
            . DIRECTORY_SEPARATOR
            . 'scripts'
            . DIRECTORY_SEPARATOR
            . strtolower(substr(get_class($controller), 0, -10))
            . DIRECTORY_SEPARATOR
            . strtolower(substr($actionName, 0, -6))
            . $this->extension;

        return $path;
    }

    /**
     * Renders the view to the screen.
     * @param FW_Controller_Action $controller The controller that wants the rendering to be done.
     * @param string $actionName The name of the action that wants the rendering to be done.
     */
    public function render(FW_Controller_Action $controller, $actionName)
    {
        $data = $this->getData();
        $path = $this->getPath($controller, $actionName);

        if (!is_file($path))
            throw new FW_View_Exception('Trying to render "' . $path . '" which doesn\'t exist.', 404);
            
        $layout = $this->getLayout();
        
        extract($data);
        
        ob_start();
        include $path;
        $source = ob_get_contents();
        if ($layout != null && $this->layoutEnabled)
            $layout->setContent($source);
        ob_end_clean();
        
        if ($layout != null && $this->layoutEnabled)
        {
			$layoutPath = $layout->getPath();
			
			if (!is_readable($layoutPath))
				throw new FW_View_Exception('Failed to read "' . $layoutPath . '".');
			
            ob_start();
            include $layoutPath;
            $source = ob_get_contents();
            ob_end_clean();
        }
        
        echo $source;
    }

    /**
     * Calls a helper function.
     * @return FW_View_Helper_Abstract
     */
    public function __call($name, $args)
    {
        $helper = $this->getHelper($name);

        return call_user_func_array(array($helper, $name), $args);
    }
}
